package com.example.proxy;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by 汤林冰 on 2016/1/12 14:22.
 */
public class DynamicProxy {
    ///////////////////////////////////////////////////////////////////////////
    // ClassLoader
    ///////////////////////////////////////////////////////////////////////////
    @Test
    public void testClassLoader() throws Exception{
        // primary type
        System.out.printf("int.class:%s\n",int.class.getClassLoader());//null
        System.out.printf("Object.class:%s\n",Object.class.getClassLoader());//null

        // primary array
        System.out.printf("int[].class:%s\n",int[].class.getClassLoader());//null
        System.out.printf("Object[].class:%s\n", Object[].class.getClassLoader());//null
    }

    @Test
    public void testClassLoader2() throws Exception{
        System.out.println(this.getClass().getClassLoader());
        System.out.println(Thread.currentThread().getContextClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println(ClassParser.getClassText(ClassLoader.getSystemClassLoader()));
        /*
        static class sun.misc.Launcher$AppClassLoader extends java.net.URLClassLoader {

            final class sun.misc.URLClassPath ucp;
            static final boolean $assertionsDisabled;

             sun.misc.Launcher$AppClassLoader([Ljava.net.URL;, java.lang.ClassLoader);

            public java.lang.Class loadClass(java.lang.String, boolean) throws java.lang.ClassNotFoundException;
            private void appendToClassPathForInstrumentation(java.lang.String);
            private static java.security.AccessControlContext getContext([Ljava.io.File;) throws java.net.MalformedURLException;
            protected java.security.PermissionCollection getPermissions(java.security.CodeSource);
            public static java.lang.ClassLoader getAppClassLoader(java.lang.ClassLoader) throws java.io.IOException;

        }
         */
    }


    ///////////////////////////////////////////////////////////////////////////
    // example 1
    ///////////////////////////////////////////////////////////////////////////
    //创建接口, java 动态代理只支持接口
    interface IHelloWorld {
       void show();
    }

    //如何操作代理的InvocationHandler --> 如何去实现接口中的抽象方法
    class HelloWorldHandler implements InvocationHandler {
        /**
         * {@inheritDoc}
         * 在代理实例上处理方法调用并返回结果
         *
         * @param proxy  Proxy.newProxyInstance产生的代理类对象
         * @param method 被代理的方法
         * @param args   该方法的参数数组
         */
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("HelloWorldHandler invoke!!!!");
            return proxy;
        }
    }

    @Test
    public void testProxy() throws Exception{
        //创建动态代理对象 --> 该对象所属的类继承自Proxy实现IHelloWorld接口
        IHelloWorld proxy=(IHelloWorld) Proxy.newProxyInstance(
                ClassLoader.getSystemClassLoader(),//类加载器
                new Class[]{IHelloWorld.class},//接口列表
                new HelloWorldHandler());
        proxy.show();
        System.out.println(ClassParser.getClassText(proxy));
        //final class com.example.$Proxy4 extends java.lang.reflect.Proxy implements
        // com.example.proxy.DynamicProxy$IHelloWorld {
    }

    ///////////////////////////////////////////////////////////////////////////
    // example 2
    // TODO 参看博文 http://jiangshuiy.iteye.com/blog/1333558
    // 应用场景 典型的日志记录、事务管理、权限等控制上
    ///////////////////////////////////////////////////////////////////////////
    interface I1{
        void method1(String str);
    }
    interface I2{
        void method2(String str);
    }
    interface I3 extends I1,I2{}

    class Imp implements I3{
        @Override
        public void method1(String str) {
            System.out.println(String.format("I1 method1(%s)", str));
        }

        @Override
        public void method2(String str) {
            System.out.println(String.format("I2 method2(%s)", str));
        }
    }
    class MyInvocationHandler implements InvocationHandler{
        Object obj;

        public MyInvocationHandler(Object obj) {
            this.obj = obj;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            System.out.println("before method");
            method.invoke(obj, args);
            System.out.println("after method");
            //相当于在原来想要调用的方法头尾嵌入了代码
            // TODO 参看博文 http://jiangshuiy.iteye.com/blog/1333558
            // 应用场景 典型的日志记录、事务管理、权限等控制上
            return obj;
        }
    }
    @Test
    public void testProxy2() throws Exception{
        //创建动态代理对象 --> 该对象所属的类继承自Proxy实现IHelloWorld接口
        Object proxy = Proxy.newProxyInstance(
                ClassLoader.getSystemClassLoader(),//类加载器 见testClassLoader2
                Imp.class.getInterfaces(),//接口列表
                new MyInvocationHandler(new Imp()));
        ((I1) proxy).method1("hello1");
        ((I2) proxy).method2("hello2");

    }
}
